package com.yeziji.job.common.log;

import com.yeziji.job.common.JobContext;
import com.yeziji.job.common.base.JobContextInfo;
import com.yeziji.utils.expansion.MessageFormat2;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.spi.LocationAwareLogger;

import java.util.Optional;

/**
 * 任务日志
 *
 * @author hwy
 * @since 2024/06/26 22:29
 **/
public class YzjJobLogger {
    private static final Object[] EMPTY_ARRAY = new Object[]{};
    private static final String FQCN = YzjJobLogger.class.getName();
    private static final Logger LOGGER = LoggerFactory.getLogger(YzjJobLogger.class);

    public static void info(String msg, Object... args) {
        log(LocationAwareLogger.INFO_INT, msg, args);
        if (JobContext.get() != null) {
            Optional.ofNullable(JobContext.get()).ifPresent(context -> context.appendLog("[INFO] " + msg, args));
        }
    }

    public static void error(String msg, Object... args) {
        log(LocationAwareLogger.ERROR_INT, msg, args);
        if (JobContext.get() != null) {
            Optional.ofNullable(JobContext.get()).ifPresent(context -> context.appendLog("[ERROR] " + msg, args));
        }
    }

    public static void warn(String msg, Object... args) {
        log(LocationAwareLogger.WARN_INT, msg, args);
        if (JobContext.get() != null) {
            Optional.ofNullable(JobContext.get()).ifPresent(context -> context.appendLog("[WARN] " + msg, args));
        }
    }

    public static void debug(String msg, Object... args) {
        log(LocationAwareLogger.DEBUG_INT, msg, args);
        if (JobContext.get() != null) {
            Optional.ofNullable(JobContext.get()).ifPresent(context -> context.appendLog("[DEBUG] " + msg, args));
        }
    }

    /**
     * 打印当前栈堆日志
     *
     * @param mode 日志模式
     * @param msg  日志信息
     * @param args 日志参数
     */
    public static void log(int mode, String msg, Object... args) {
        getLogger().log(null, FQCN, mode, getMsg(msg, args), EMPTY_ARRAY, null);
    }

    /**
     * 获取当前堆栈上的日志
     *
     * @return {@link LocationAwareLogger}
     */
    private static LocationAwareLogger getLogger() {
        Optional<String> stackClassOpt = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
                .walk(s -> s.skip(2).limit(1).map(StackWalker.StackFrame::getClassName).findFirst());
        if (stackClassOpt.isPresent()) {
            return (LocationAwareLogger) LoggerFactory.getLogger(stackClassOpt.get());
        }
        return (LocationAwareLogger) LOGGER;
    }

    /**
     * 解析实际日志的信息
     *
     * @param msg  日志信息
     * @param args 日志信息参数
     * @return {@link String} 实际日志信息
     */
    private static String getMsg(String msg, Object... args) {
        if (args != null && args.length > 0) {
            msg = MessageFormat2.formatTuple(msg, args);
        }
        return msg;
    }

    /**
     * 清除线程对象
     * <p>
     *     清除之前先把数据更新到 context 中
     * </p>
     * @deprecated 会造成重复添加
     */
    public static void clear() {
        if (JobContext.get() != null) {
            // thread local info
            JobContextInfo jobContextInfo = JobContext.get();
            final String flag = jobContextInfo.getFlag();
            // append logger then update context
            JobContextInfo originContext = JobContext.get(flag);
            originContext.appendLog(jobContextInfo.getLogMsg());
            originContext.appendExceptionLog(jobContextInfo.getExceptionMsg());
            JobContext.update(flag, originContext);
        }
    }
}
